// WebSocket连接地址
var wsRun   = "ws://10.128.221.159:8080/websocket/name",
    wsDebug = "ws://echo.websocket.org/";

// WebSocket连接
var ws = new WebSocket(1 ? wsDebug : wsRun);

$().ready(() => {
    // 初始化
    init();
    // 设置WebSocket回调
    setWebSocketCallback(ws);
});

// 网络初始化
init = () => {
    // 重置图表高度
    loadChartHeight();
    // 图表显示loading
    for (let i = 0; i < chartDOMList.length; i++) {
        eval("chart" + i + ".showLoading()");
    }
    // 显示内容
    $("div.contents").css("visibility", "visible");
}

// WebSocket回调
setWebSocketCallback = () => {
    ws.onopen = (e) => {
        s = $.format("({0}) websocket successfully open", new Date().Format("yyyy-MM-dd hh:mm:ss"));
        console.log(s);
        // 执行调试JS
        if (ws.url === wsDebug) {
            demo0();
        } else {
            ws.send(JSON.stringify({
                "key": "hello",
                "value": ""
            }));
        }
    }
    ws.onmessage = (e) => {
        s = $.format("({0}) websocket recieve message: {1}", new Date().Format("yyyy-MM-dd hh:mm:ss"), e.data);
        // console.log(s);
        // 根据数据执行对应方法
        try {
            obj = $.parseJSON(e.data);
            value = obj.value;
            method = switchMap.get(obj.key);
            eval(method + "(" + JSON.stringify(value) + ")"); 
        } catch (err) {
            s = $.format("({0}) wrong message type:", new Date().Format("yyyy-MM-dd hh:mm:ss"));
            console.log(s);
            console.log(err);
            ws.close();
        }
    }
    ws.onclose = (e) => {
        s = $.format("({0}) websocket close", new Date().Format("yyyy-MM-dd hh:mm:ss"));
        console.log(s);
    }
    ws.onerror = (e) => {
        s = $.format("({0}) websocket error: {1}", new Date().Format("yyyy-MM-dd hh:mm:ss"), e.error);
        console.log(s);
    }
}

loadChartHeight = () => {
    // 初始化各图表height
    let windowHeight        = $(document.body).height();
    let navHeight           = windowHeight * 0.1;
    let comNetHeight        = windowHeight * 0.6;
    let liveHeight          = comNetHeight * 0.55;
    let netDynamicHeight    = comNetHeight * 0.45 - 5;
    let elseHeiht           = windowHeight - comNetHeight - navHeight;
    $("#comnet-body")       .css("height", comNetHeight);
    $("#live-body")         .css("height", liveHeight);
    $("#netdynamic-body")   .css("height", netDynamicHeight);
    $("#task-body")         .css("height", elseHeiht);
    for (let i = 0; i < chartDOMList.length; i++){
        eval("chart" + i + ".resize()");
    }
}

// 收到hello消息时
onHello = () => {
    for (let i = 0; i < chartDOMList.length; i++) {
        eval("chart" + i + ".hideLoading()");
    }
};

// 收到任务统计信息时
onStatTask = (v) => {
    let task = v.task;
    // 更新task
    task.deadline   = task.deadline + "ms";
    task.duration   = task.delay + "ms";
    task.efficiency = Number(task.efficiency).toFixed(2) + "%";
    // 更新LIVE
    updateLive(task);
    // 更新TaskDynamicChart
    updateTaskDynamic(v);
    // 更新TaskStatChart
    updateTaskStat(v);
    // 更新TaskFlowTable
    updateTaskFlow(v);
}

// 收到网络统计信息时
onStatNet = (v) => {
    let comNet  = v.comNet;
    let id      = comNet.id;
    let nodes   = comNet.nodes;
    let links   = comNet.links;
    let graph   = [];
    nodesNum    = nodes.length;
    for (let i = 0; i <= nodesNum; i++) {
        graph.push([new Array(nodesNum + 1)].fill(0));
    }
    for (let i = 0; i < links.length; i++) {
        let l = links[i];
        if (l.nodeDes <= nodesNum && l.nodeSrc <= nodesNum) {
            graph[l.nodeSrc][l.nodeDes] = [l.nodeDes, l.nodeSrc, l.rate, l.esDelay];
        }
    }
    for (let i = 1; i < graph.length; i++){
        graph[i][i] = nodes[i - 1].restComputing.concat(nodes[i - 1].restStorage);
    }
    comNet.id = new Date(Number(id)).Format("hh:mm:ss");
    comNet.graph = graph;
    updateComNet(comNet);
    updateNetDynamic(v);
}

// 更新算力网络图
updateComNet = (comNet) => {
    let graph   = comNet.graph;
    let data    = [], links = [];
    let krd     = $.getKrd(nodesNum, 300, 300, 500, 0.55);
    for (let i = 1; i < graph.length; i++) {
        let nodeVal = $.format('Node Info:\n[Computing Resource]\nKernels: {0}K, Freq: {1}GHz, Utils: {2}%\n[Storage Resource]\n Storages: {3}MB, Utils: {4}%', graph[i][i]);
        datum = {   name: $.format('Edge Node {0}', i), 
                    x: krd[i - 1][0], y: krd[i - 1][1], 
                    value: nodeVal, symbol : 'path://' + SERVER_SVG, 
                    itemStyle : {color: $.getGradientColor(Number(graph[i][i][2] + graph[i][i][4]) / 2, 1)}
                };
        data.push(datum);
        for (let j = 1; j < graph.length; j++) {
            if (i != j && graph[i][j] != undefined) {
                let linkVal = $.format("Link Info:\n[Edge]\nNode Src: {0}, Node Dest: {1}\n[Transmission]\nRate: {2}Mbps, Establishment Delay: {3}ms", graph[i][j]);
                let linkLabel = $.format("({0}Mbps, {1}ms)", graph[i][j][2], graph[i][j][3]);
                let width = Math.log(Number(graph[i][j][2]) + 1.6) / Math.log(1.6);
                link =  {   name: $.format('Link {0}→{1}', i - 1, j - 1), source: i - 1, target: j - 1, 
                            label: { show: true, formatter: linkLabel}, 
                            value: linkVal, lineStyle: {width: width}
                        };
                links.push(link);
            }
        }
    }
    chart0.setOption({
        series: [{
            data: data,
            links: links,
        }]
    });
}

updateLive = (task) => {
    let timestamps = task.timestamps;
    $("#task-arrive-time")  .html(timestamps[0]);
    $("#task-finish-time")  .html(timestamps[timestamps.length - 1]);
    $("#task-duration")     .html(task.duration);
    $("#task-deadline")     .html(task.deadline);
    $("#task-efficiency")   .html(task.efficiency);
    $("#task-id")           .html(task.id);
    $("#task-pairs")        .html(task.pairs);
    $("#task-type")         .html(task.typeAbbr);
    $("#task-result")       .html(task.result);
    $("#snapshot")          .attr("src", task.snapshot);
}

// 更新表格
updateTaskFlow = (v) => {
    let s = "";
    let taskFlow = v.taskFlow;
    for (let i = 0; i < 5; i++) {
        s += $.format("<td>{0}</td>", taskFlow[i]);
    }
    if ($("tbody tr").length >= 5) {
        $("tbody tr").last().remove();
    }
    $("tbody").prepend($.format("<tr>{0}</tr>", s));
}

// 更新任务动态图表
updateTaskDynamic = (v) => {
    let series1 = [];
    let series2 = [];
    let xAxis   = v.xAxisDynamic;
    let dataTaskDynamic1 = v.taskDelay.yValue;
    let dataTaskDynamic2 = v.taskEff.yValue;
    for (let k in dataTaskDynamic1) {
        series1.push({name:k, data: dataTaskDynamic1[k]});
    }
    for (let k in dataTaskDynamic2) {
        series2.push({name:k, data: dataTaskDynamic2[k]})
    }
    
    chart3.setOption({
        xAxis: {
            data: xAxis
        },
        series: series1
    });
    chart4.setOption({
        xAxis: {
            data: xAxis
        },
        series: series2
    });
}

// 更新任务统计图表
updateTaskStat = (v) => {
    let series1 = [];
    let series2 = [];
    let series3 = [];
    let dataTaskStat1 = v.taskDelayDist.yValue;
    let dataTaskStat2 = v.taskEffDist.yValue;
    let dataTaskStat3 = v.taskComposition.yValue;
    for (let k in dataTaskStat1) {
        series1.push({name:k, data: dataTaskStat1[k]});
    }
    for (let k in dataTaskStat2) {
        series2.push({name:k, data: dataTaskStat2[k]})
    }
    for (let k in dataTaskStat3) {
        series3.push({name:k, value: dataTaskStat3[k]})
    }
    chart5.setOption({
        series: series1
    });
    chart6.setOption({
        series: series2
    });
    chart7.setOption({
        series: {
            name:'Network',
            data: series3
        }
    });
}

// 更新网络动态图表
updateNetDynamic = (v) => {
    let series1 = [];
    let series2 = [];
    let xAxis   = v.xAxisDynamic;
    let dataNetDynamic1 = v.netComputing.yValue;
    let dataNetDynamic2 = v.netStorage.yValue;
    let computingColor  = $.getGradientColor(v.comNet.network.computing, 1.8);
    let storageColor    = $.getGradientColor(v.comNet.network.storage, 1.8)
    for (let k in dataNetDynamic1) {
        series1.push({
            name:k, data: dataNetDynamic1[k],
            itemStyle: {
                color: computingColor
            },
            areaStyle: {
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
                    offset: 0,
                    color: computingColor
                }, {
                    offset: 1,
                    color: '#ffe'
                }])
            },
        });
    }
    for (let k in dataNetDynamic2) {
        series2.push({
            name:k, data: dataNetDynamic2[k],
            itemStyle: {
                color: storageColor
            },
            areaStyle: {
                color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
                    offset: 0,
                    color: storageColor
                }, {
                    offset: 1,
                    color: '#ffe'
                }])
            },
        })
    }
    chart1.setOption({
        xAxis: {
            data: xAxis
        },
        series: series1
    });
    chart2.setOption({
        xAxis: {
            data: xAxis
        },
        series: series2
    });
}